package mroute

import (
	"github.com/gin-gonic/gin"
	"mygo/mymongo"
	"mygo/mystruct"
	"mygo/global"
	"os"
	"fmt"
	//"time"
	"encoding/json"
	"path/filepath"
	"mime/multipart"
	"strings"
	//"encoding/json"
)



/* =================================================================================
   项目接口接口[不提供代码的编辑查看保存接口这个在route_code里已实现]
   接口实现【创建/删除】目录文件
   查看树状信息
*/
func MypackModel(cont *gin.Context) {
	code := cont.PostForm("code")
   codb := mymongo.Get_Code(code)
   if codb == nil {
   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "标识不存在"})
   	return	
   }
   model := cont.PostForm("model")
   queryid := cont.PostForm("id")
   name  := cont.PostForm("name")
   path  := cont.DefaultPostForm("path", "")
   value := cont.DefaultPostForm("value", "")

   rootPath := filepath.Join(global.Mtoken.Download_Path, codb.Body.Apiid, queryid, name)

   if !mystruct.Exists(rootPath) {
   	value := mystruct.FindItemsByName(codb.Body.Data, name)
   	if value.Select != "pack" {
   		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "项目不存在"})
			return
   	}
		if err := os.MkdirAll(rootPath, 0777); err != nil {
      	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("项目初始化失败: %v", err)})
         return
      }
	}

   switch model {
	   case mystruct.PACK_CREATE_DIR:
	   	if value == "" {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "不能创建空名称目录"})
            return
        	}
        	fullPath := filepath.Join(rootPath, path, value)
	   	if err := os.MkdirAll(fullPath, 0777); err != nil {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("创建目录失败: %v", err)})
            return
        	}
	   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "目录创建完成"})

	   case mystruct.PACK_CREATE_FILE:
	   	if value == "" {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "不能创建空名称文件"})
            return
        	}
        	fullPath := filepath.Join(rootPath, path, value)
	   	if err := os.WriteFile(fullPath, []byte{}, 0777); err != nil {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("创建文件失败: %v", err)})
            return
        	}
	   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "文件创建完成"})

	   case mystruct.PACK_DELETE_DIR:
	   	if value == "" {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "dir参数不能为空"})
            return
        	}
        	fullPath := filepath.Join(rootPath, path, value)
        	if err := os.RemoveAll(fullPath); err != nil {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("删除目录失败: %v", err)})
            return
        	}
	   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "目录删除完成"})

	   case mystruct.PACK_DELETE_FILE:
	   	if value == "" {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "file参数不能为空"})
            return
	      }
	      fullPath := filepath.Join(rootPath, path, value)
	      if err := os.Remove(fullPath); err != nil {
	         cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("删除文件失败: %v", err)})
	         return
	      }
	      cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "文件删除完成"})

	   case mystruct.PACK_ALL:
	   	rootPath = filepath.Join(rootPath, path)
	   	if !mystruct.Exists(rootPath) {
	   		cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "目录不存在"})
	   		return
	   	}
	   	tree := buildDirTreeEnhanced(rootPath, rootPath)
			cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": tree})

		case mystruct.PACK_RENAME:
			if value == "" {
            cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "不能命名为空"})
            return
	      }
			oldpath := filepath.Join(rootPath, path)
			newpath := filepath.Join(rootPath, filepath.Dir(path), value)
			if err := os.Rename(oldpath, newpath); err != nil {
				cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("修改失败: %v", err)})
				return
			}
			cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "修改成功"})

		case mystruct.PACK_UPLOAD_FILE:
			node_path := filepath.Join(rootPath, path)
			if !mystruct.Exists(node_path) {
				cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("节点不存在: %s", path)})
				return
			}
			var jsonContent map[string]string
    		json.Unmarshal([]byte(value), &jsonContent);
    		var map_files = make(map[string]*multipart.FileHeader) 
    		for formField, savePath := range jsonContent {
    			safePath := filepath.Clean(savePath)
    			if strings.Contains(safePath, "..") {
    				cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": fmt.Sprintf("非法路径: %s", safePath)})
    				return
    			}
    			file, err := cont.FormFile(formField)
	        	if err != nil {
	            cont.JSON(mystruct.StatusOK, gin.H{
	               "code": mystruct.MyCodeErr,
	               "msg":  fmt.Sprintf("文件 '%s' 获取失败", formField),
	            })
	            return
	        	}
	        	map_files[filepath.Join(node_path, safePath)] = file
    		}
    		for fp, fe := range map_files {
    			os.MkdirAll(filepath.Dir(fp), 0777)
    			if err := cont.SaveUploadedFile(fe, fp); err != nil {
	            cont.JSON(mystruct.StatusOK, gin.H{
	               "code": mystruct.MyCodeErr,
	               "msg":  fmt.Sprintf("文件 '%s' 保存失败", SafeStripBasePath(fp, node_path)),
	            })
	            return
	        }
    		}
			cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeOk, "msg": "上传完成"})

	   default:
	   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "不支持的model参数"})
   }
}

func Export_Pack(cont *gin.Context) {
	code := cont.Query("code")
	queryid := cont.Query("_id")
   name := cont.Query("name")

   codb := mymongo.Get_Code(code)
   if codb == nil {
   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "标识不存在"})
   	return	
   }
   
   file_Path := filepath.Join(global.Mtoken.Download_Path, codb.Body.Apiid, queryid, name)
   if !mystruct.Exists(file_Path) {
   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "项目不存在"})
   	return
   }
   zip_Path := filepath.Join(global.Mtoken.Download_Path, codb.Body.Apiid, queryid, "data.zip")
   if err := mystruct.ZipDirectory(file_Path, zip_Path); err != nil {
   	cont.JSON(mystruct.StatusOK, gin.H{"code": mystruct.MyCodeErr, "msg": "压缩失败: " + err.Error()})
   	return
   }
   defer func() {
   	os.Remove(zip_Path)
    }()
   cont.Header("Content-Type", "application/octet-stream")
	cont.Header("Content-Transfer-Encoding", "binary")
	cont.Header("Cache-Control", "no-cache")
	cont.Header("Content-Disposition", "attachment; filename=data.zip")
	cont.Header("Content-Length", fmt.Sprintf("%d", mystruct.GetFileSize(zip_Path)))
   cont.File(zip_Path)
  	return
}

func buildDirTreeEnhanced(root string, basePath string) map[string]interface{} {
	tree := make(map[string]interface{})
	entries, err := os.ReadDir(root)
	if err != nil {
		tree["error"] = err.Error()
		return tree
	}
	var files []map[string]interface{}
	var dirs []map[string]interface{}
	for _, entry := range entries {
		fullPath := filepath.Join(root, entry.Name())
		if entry.IsDir() {
			dirs = append(dirs, buildDirTreeEnhanced(fullPath, basePath))
		} else {
			fileInfo, err := entry.Info()
			if err != nil {
				continue // or handle error as you prefer
			}
			fileData := map[string]interface{}{
				"name":     entry.Name(),
				"size":     fileInfo.Size(),
				"path":		SafeStripBasePath(fullPath, basePath),
				"modTime":  fileInfo.ModTime().Format("2006-01-02 15:04:05"),
				"isDir":    false,
			}
			files = append(files, fileData)
		}
	}
	if len(files) > 0 {
		tree["files"] = files
	}
	if len(dirs) > 0 {
		tree["dirs"] = dirs
	}
	tree["path"] = SafeStripBasePath(root, basePath)
	tree["name"] = filepath.Base(root)
   tree["isDir"] = true
	return tree
}

func SafeStripBasePath(filePath, basePath string) string {
	relative := filePath[len(basePath):]
	if len(relative) > 0 && relative[0] == '/' {
		relative = relative[1:]
	}
	relative = filepath.FromSlash(relative)
	
	return relative
}